package com.nyt.report.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Lists;
import com.nyt.report.constant.Methods;
import com.nyt.report.constant.Status;
import com.nyt.report.model.ApiUser;
import com.nyt.report.model.StationConfig;
import com.nyt.report.model.SysApiStation;
import com.nyt.report.model.request.PublicRequest;
import com.nyt.report.model.response.BaseResponse;
import com.nyt.report.model.response.PublicResponse;
import com.nyt.report.service.CacheService;
import com.nyt.report.service.KafkaService;
import com.nyt.report.util.DateUtil;
import com.nyt.report.util.HttpUtil;
import com.nyt.report.util.SignKit;
import com.nyt.report.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;

import java.nio.charset.Charset;
import java.util.List;


/**
 * 验签过滤器
 *
 */
@WebFilter(urlPatterns = "/sync")
public class SignCheckFilter implements Filter {

    // 异常信息收集
    Logger errLog = LoggerFactory.getLogger("errorLogger");

    // 普通日志收集
    Logger infoLog = LoggerFactory.getLogger("infoLogger");


    @Autowired
    CacheService cacheService;

    @Autowired
    KafkaService kafkaService;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        infoLog.info("sign check filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException {
        HttpServletRequest httpRequeset = (HttpServletRequest) servletRequest;
        System.out.println("**************  httpRequeset为："+httpRequeset);
        // 获取请求的IP
        String IPAddr = HttpUtil.getClientIp(httpRequeset);
        // 读取请求参数
        String jsonStr = getRequestStr(httpRequeset);
        // 转换成对象处理
        JSONObject reqData = JSON.parseObject(jsonStr);
        PublicRequest publicReq = reqData.getObject("publicrequest", PublicRequest.class);

        // body可能为非数组，统一转换数组处理
        String bodytemp = "";
        Object body = reqData.get("body");
        if (body instanceof List) {         // 判断上传的是否数组
            // 获得bodytemp
            bodytemp = JSON.toJSONString(body, SerializerFeature.MapSortField, SerializerFeature.DisableCircularReferenceDetect);
            // 然后封装成统一格式
            JSONObject jsonObj = new JSONObject();
            jsonObj.put("data", body);
            jsonObj.put("total", ((List)body).size());
            body = jsonObj;
        }
        else {
            // 获得bodytemp
            bodytemp = JSON.toJSONString(body, SerializerFeature.MapSortField, SerializerFeature.DisableCircularReferenceDetect);
        }

        //开始验签逻辑
        try {
            // requesttime 是否在15分钟内
            if (!DateUtil.isDiffInMins(publicReq.getRequesttime(), 15)){
                doResponse(servletResponse, publicReq, "10001");
                return;
            }

            // 查找secretkey
//            StationConfig station = cacheService.queryStationConfig(publicReq.getAccesskey());
//            if (station == null) {
//                doResponse(servletResponse, publicReq, "10002");
//                return;
//            }
            ApiUser station = cacheService.queryApiUser(publicReq.getAccesskey());
            if (station == null) {
                doResponse(servletResponse, publicReq, "10002");
               return;
            }
            //IP验证 2019-08-01
            String ipWhiteList = station.getIp_whitelist();
            if( !Lists.newArrayList(ipWhiteList.split(",")).contains(IPAddr)){
                doResponse(servletResponse,publicReq,"10007",String.format("IP[%s]不允许访问!", IPAddr));
            }
            //判断ip对应站点是否允许上报 2019-08-01
            String reserve = publicReq.getReserve();//站点目标编码
            System.out.println("IP是："+IPAddr);
            System.out.println("站点目标编码："+reserve);
            if( ! reserve.equalsIgnoreCase("19940814nyt")){
                SysApiStation sysApiStation = cacheService.getStationWhitelist(IPAddr);
                if( sysApiStation == null ){
                    doResponse(servletResponse, publicReq, "10008");
                    return;
                }
                //站点验证
                String stationWhiteList = sysApiStation.getStation_whitelist();
                if( ! Lists.newArrayList(stationWhiteList.split(",")).contains(reserve) ){
                    doResponse(servletResponse, publicReq, "10009",String.format("站点[%s]不允许访问!", reserve));
                    return;
                }

            }



            // requestid 是否存在集合中
//            if (cacheService.exitRequestid(publicReq.getRequestid(), IPAddr)){
//                doResponse(servletResponse, publicReq, "10003");
//                return;
//            }
            if (!StringUtils.isBlank(cacheService.search("requestIdCache", publicReq.getRequestid(), String.class))){
                doResponse(servletResponse, publicReq, "10003");
            }else {
                cacheService.save("requestIdCache", publicReq.getRequestid(), publicReq.getRequestid());
            }


            // 判断接口是否在集合中
            if (!Methods.exist(publicReq.getMethod())){
                doResponse(servletResponse, publicReq, "10005");
                return;
            }


            if ("MD5".equals(publicReq.getSignmethod())) {
                // 开始验签
                Boolean isSign = SignKit.checkSignature(publicReq.getSigndata(), publicReq.getAccesskey(),
                        station.getSecretkey(), bodytemp, publicReq.getRequestid(), publicReq.getRequesttime());
                if (isSign) {
                    // 验签成功，把body放入kafka，主题为：客运站编码首字母_上报方法
                    kafkaService.publishMsg(publicReq.getMethod(), ((JSONObject) body).toJSONString());
                    doResponse(servletResponse, publicReq, "00000");
                    return;
                }
                doResponse(servletResponse, publicReq, "10004");
                return;
            }
            else {  // 非MD5，验签失败，丢弃数据
                doResponse(servletResponse, publicReq, "10004");
                return;
            }

            // 判断客运站编码是否符合规范
//            String stationcode = body.size()>0 ? body.getJSONObject(0).getString("submitstationcode").substring(0,1) : "";
//            String standardcode = body.size()>0 ? body.getJSONObject(0).getString("submitstationstandardcode") : "";

//             if (CityCodes.exist(stationcode, standardcode)) {
//            if(true) {
//                // 开始验签
//                Boolean isSign = SignKit.checkSignature(publicReq.getSigndata(), publicReq.getAccesskey(),
//                        station.getSecretkey(), bodytemp, publicReq.getRequestid(), publicReq.getRequesttime());
//
//                if ("MD5".equals(publicReq.getSignmethod()) && isSign) {
//                    // 验签成功，把body放入kafka，主题为：客运站编码首字母_上报方法
//                    body.forEach(jsonObject -> {
//                        kafkaService.publishMsg(stationcode + "_" + publicReq.getMethod(), ((JSONObject) jsonObject).toJSONString());
//                    });
//                    doResponse(servletResponse, publicReq, "00000");
//                    return;
//                }
//                else {  // 非MD5，验签失败，丢弃数据
//                    doResponse(servletResponse, publicReq, "10004");
//                    return;
//                }
//            }
//            infoLog.info("上报数据内容为空或客运站编号异常, accesskey："+publicReq.getAccesskey());
//            doResponse(servletResponse, publicReq, "10006");
//            return;
        }
        catch (Exception e) {
            errLog.error("验签程序异常，json: \n" + jsonStr);
            doResponse(servletResponse, publicReq, "99999");
            errLog.error("验签程序异常，json: \n" + e);
            return;
        }
    }

    @Override
    public void destroy() {
        infoLog.info("sign check filter destory！！！");
    }

    private void doResponse(ServletResponse response,PublicRequest publicReq, String statuscode) {
        Writer writer = null;
        try {
            if(!"00000".equals(statuscode)) {  // 日志
                infoLog.info("验签失败, 错误代码："+ statuscode +", 错误信息："+ Status.getMsg(statuscode)
                        +", accesskey："+publicReq.getAccesskey());
            }

            // 准备返回信息
            BaseResponse respData = new BaseResponse(
                    new PublicResponse(publicReq.getMethod(), publicReq.getAccesskey(), publicReq.getRequestid(),
                            DateUtil.nowFormat("yyyyMMddHHmmss"), statuscode, Status.getMsg(statuscode), ""),
                    null);
            response.setCharacterEncoding("UTF-8");
            writer = response.getWriter();
            writer.write(JSON.toJSONString(respData));
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if (writer!=null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private void doResponse(ServletResponse response, PublicRequest publicReq, String statuscode, String msg) {
        Writer writer = null;
        try {
            if (!"00000".equals(statuscode)) {  // 日志
                infoLog.info("验签失败, 错误代码：" + statuscode + ", 错误信息：" + Status.getMsg(statuscode)
                        + ", accesskey：" + publicReq.getAccesskey());
            }

            // 准备返回信息
            BaseResponse respData = new BaseResponse(
                    new PublicResponse(publicReq.getMethod(), publicReq.getAccesskey(), publicReq.getRequestid(),
                            DateUtil.nowFormat("yyyyMMddHHmmss"), statuscode, msg, ""),
                    null);
            response.setCharacterEncoding("UTF-8");
            writer = response.getWriter();
            writer.write(JSON.toJSONString(respData));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 获取request中的请求参数
     *
     * @param request
     * @return
     */
    private String getRequestStr(HttpServletRequest request) {
        StringBuffer jsonParam = new StringBuffer();
        BufferedReader reader = null;
        try {
            if (request.getContentLength() > 0) {
                reader = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
                String line = "";
                while ((line = reader.readLine()) != null)
                    jsonParam.append(line);
                reader.close();
            }
        } catch (IOException e) {
            errLog.error("参数转换成json异常g{}", e);
        }
        finally {
            if (reader!=null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    errLog.error("json转换成功，但是inputstream.close异常: ", e);
                }
            }
        }
        return jsonParam.toString();
    }
}
